/**
参考网址：https://blog.csdn.net/qq_43766999/article/details/120527511?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-120527511-blog-119205448.235%5Ev38%5Epc_relevant_sort_base3&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-120527511-blog-119205448.235%5Ev38%5Epc_relevant_sort_base3&utm_relevant_index=1
地图划线LineString，多个点图标
并可以查找最近的点
*/

<template>
    <div id="content">
        <div id="map" ref="map"/>
    </div>
</template>

<script>
    import "ol/ol.css";
    import {Map, Feature, View} from "ol";
    import {getDistance} from "ol/sphere";
    // import * as Sphere from "ol/sphere";

    // import * as olProj from "ol/proj";
    import TileLayer from "ol/layer/Tile";
    import VectorLayer from "ol/layer/Vector";
    import VectorSource from "ol/source/Vector";
    import {Style, Stroke, Icon, Fill, Text, Circle as CircleStyle} from "ol/style";
    import {LineString, Point} from "ol/geom";
    // import {circular} from "ol/geom/Polygon";
    import XYZ from "ol/source/XYZ";
    import {fromLonLat, toLonLat} from "ol/proj";
    import {convertXYToGPS} from "./func";

    export default {
        data() {
            return {
                map: null,
                randPointLayer: null,
                findPointVectorCache: [],
                arr: [
                    {sn: '001', name: 'name001', lon: 113.54381132, lat: 22.26603718},
                    {sn: '002', name: 'name002', lon: 113.54210586, lat: 22.24522491},
                    {sn: '003', name: 'name003', lon: 113.54272867, lat: 22.25908172},
                    {sn: '004', name: 'name004', lon: 113.52521249, lat: 22.28296649},
                    {sn: '005', name: 'name005', lon: 113.53888402, lat: 22.26633718},
                    {sn: '006', name: 'name006', lon: 113.56272589, lat: 22.28156777},
                    {sn: '007', name: 'name007', lon: 113.56545975, lat: 22.27349332},
                ],
            };
        },
        mounted() {
            this.initMap(); //初始化地图
            this.createLineString();
        },
        methods: {
            createLineString() {
                let arr = this.arr.map(function (data) {
                    return fromLonLat([data.lon, data.lat])
                });

                // 创建一个 线元素
                let lineFeature = new Feature({
                    geometry: new LineString(arr),
                    type: 'lineString', // 指定type属性，用于匹配style，以及在feature点击事件中做出不同的操作
                });
                // 还可以添加起点和终点
                let startFeature = new Feature({
                    geometry: new Point(arr[0]),
                    type: 'startPoint',
                });
                let endFeature = new Feature({
                    geometry: new Point(arr[arr.length - 1]),
                    type: 'endPoint',
                });

                // 创建一个矢量层
                let lineLayer = new VectorLayer({
                    source: new VectorSource({
                        features: [startFeature, lineFeature, endFeature],
                    }),
                    style: (feature) => {
                        return getStyle(feature.get('type'));
                    },
                    zIndex: 1,
                });
                // 往地图实例中加入改层
                this.map.addLayer(lineLayer);

                // 封装一下feature样式
                function getStyle(type) {
                    switch (type) {
                        case 'lineString':
                            return new Style({
                                stroke: new Stroke({
                                    width: 5, 		  // 线宽
                                    color: '#27BB53', // 线的颜色
                                })
                            });
                        case 'startPoint':
                            return new Style({
                                stroke: new Icon({
                                    src: require('@/assets/img/start.png'),  // 起点图标src
                                    scale: 1,		  // 缩放比例,默认为 1
                                    opacity: 1, 		  // 透明度,默认为 1
                                    offset: [0, 0], 	  // 偏移,默认为 [0, 0]
                                })
                            });
                        case 'endPoint':
                            return new Style({
                                stroke: new Icon({
                                    src: require('@/assets/img/end.png'), // 终点图标src
                                    scale: 1,
                                    opacity: 1,
                                    offset: [0, 0],
                                }),

                                // image: new CircleStyle({
                                //     radius: 12, fill: new Fill({ color: '#FF0000', })
                                // }),
                                // image: new Icon({
                                //     scale: 0.8,
                                //     src: require('@/assets/img/end.png'),
                                //     anchor: [0.48, 0.52],
                                //     imgSize: [10, 5]
                                // }),
                            });
                        default:
                            return null;
                    }
                }
            },

            drawRandPoint(start, e) {
                if (this.randPointLayer) {
                    this.randPointLayer.getSource().clear();
                    this.randPointLayer = null;
                    this.map.removeLayer(this.randPointLayer);
                }
                if (this.findPointVectorCache) {
                    this.findPointVectorCache.map((findPointVector) => {
                        // findPointVector.getSource().clear();
                        // findPointVector = null; //这些可以不需要，只要删除层就可以
                        this.map.removeLayer(findPointVector);
                    })
                    this.findPointVectorCache.clear;
                }
                this.randPointLayer = new VectorLayer({
                    className: 'randPointClass',
                    source: new VectorSource(),
                });
                const feature = new Feature({
                    geometry: new Point(e.coordinate),
                });

                let styleIcon = new Style({
                    // image: new CircleStyle({
                    //     radius: 12, fill: new Fill({ color: '#FF0000', })
                    // }),
                    image: new Icon({
                        scale: 0.8,
                        src: require('@/assets/img/icon-water-red.png'),
                        anchor: [0.48, 0.52],
                        //   imgSize: [80, 50]
                    }),
                });
                let dfm = convertXYToGPS(start)
                feature.obj = {
                    id: '0000',
                    water_name: '随机定位',
                    east_longi_d: start[0],
                    north_lati_d: start[1],
                    east_longi: dfm[0],
                    north_lati: dfm[1]
                };
                feature.setStyle(styleIcon);
                this.randPointLayer.getSource().addFeatures([feature]);
                // 添加图层
                this.map.addLayer(this.randPointLayer);
            },

            drawFindPoint(findPoint) {
                console.log('findPoint:  ', findPoint.lon, findPoint.lat)
                var startF = new Feature(new Point(fromLonLat([findPoint.lon, findPoint.lat])));
                startF.obj = {};//注意：需要实例化
                startF.obj.name = findPoint.name;

                var features = [startF];
                var vectorSource = new VectorSource({
                    features: features
                });
                let findPointVector = new VectorLayer({
                    className: 'findPointClassName',
                    source: vectorSource,
                    style: function (feature) {
                        var _color = "red";
                        var _name = feature.obj.name;

                        return new Style({
                            image: new CircleStyle({
                                radius: 15,
                                fill: new Fill({
                                    color: _color,
                                })
                            }),
                            stroke: new Stroke({
                                color: _color,
                                width: 5,
                                lineDash: [10, 8]
                            }),
                            text: new Text({
                                text: _name,
                                font: "bold 15px 微软雅黑",
                                fill: new Fill({
                                    color: 'red'
                                }),
                                // textAlign: "center",
                                textAlign: "left",
                                // textBaseline: "middle"
                                textBaseline: "alphabetic"
                            })
                        });//#return
                    }
                });//#vector
                this.findPointVectorCache.push(findPointVector)
                this.map.addLayer(findPointVector);
            },
            /**
             * 初始化一个 openlayers 地图
             */
            initMap() {
                const target = "map"; // 跟页面元素的 id 绑定来进行渲染
                const tileLayer = [
                    new TileLayer({
                        source: new XYZ({
                            url: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",
                        }),
                        projection: "EPSG:3857",

                    }),
                ];
                this.map = new Map({
                    target: target, // 绑定dom元素进行渲染
                    view: new View({
                        // center: olProj.fromLonLat([113.00000000, 22.00000000]),
                        center: [12640084.898763862, 2544402.9407081595],
                        zoom: 13,
                    }),
                    layers: tileLayer,
                    controls: [],
                });

                // 可以通过监听地图click事件，获取地图点击时候的坐标，用作测试数据
                this.map.on('singleclick', e => {
                    console.log('click the map get coordinate', toLonLat(e.coordinate));
                    let start = toLonLat(e.coordinate)
                    let minMax = getPath(this.arr, start)
                    console.log(minMax);

                    this.drawRandPoint(start, e);
                    let recently = minMax[0];
                    let farthest = minMax[this.arr.length - 1];
                    for (let index = 0; index < this.arr.length; index++) {
                        if (this.arr[index].lon == recently.lon && this.arr[index].lat == recently.lat) {
                            console.log('recently ponit find: ', recently)
                            this.drawFindPoint(recently)
                        }

                        if (this.arr[index].lon == farthest.lon && this.arr[index].lat == farthest.lat) {
                            console.log('farthest ponit find: ', farthest)
                            this.drawFindPoint(farthest)
                        }
                    }
                });


            },
        },
    };

    // 多个坐标点排序
    function getPath(arr, start) {
        // ol能力，通过经纬度计算距离
        // const wgs84Sphere = new Sphere(6378137);
        // let circle4326 = new circular(new Sphere(6378137), [110.1, 35.2], 300, 64)
        // let circle3857 = circle4326.clone().transform('EPSG:4326', 'EPSG:3857')
        // console.log('circle3857:   ', circle3857);

        let path = []; //最终排序结果

        // 1.指定其中某个点为起点，就以第一个点为起点
        graphSort(arr, start);

        return path;

        /**
         * 根据特定算法返回距离某点最近的一个点
         * @param ps 要排序的点集合
         * @param s 起点
         */
        function graphSort(ps, s) {
            // 先过滤一下属性
            let arr = ps.map(item => {
                let lonLat = [item.lon, item.lat];
                // 计算每个点距离中心的距离
                let distance;
                if (s === lonLat) {
                    distance = 0;
                } else {
                    distance = getDistance(s, lonLat);
                }
                return {
                    sn: item.sn,
                    name: item.name,
                    lon: item.lon,
                    lat: item.lat,
                    distance,
                }
            });

            // 根据distance排序
            arr.sort(function (a, b) {
                return a.distance - b.distance;
            });

            path.push(arr[0]); // 加入路径
            arr.splice(0, 1);// 删除第一个元素

            // 判断是否需要递归继续排序添加
            if (arr.length > 1) {
                graphSort(arr, s)
            } else {
                path.push(arr[0]);
            }
        }

        // function getDistance(lonAntLat1, lonAndLat2) {
        //     return parseInt(wgs84Sphere.haversineDistance(lonAntLat1, lonAndLat2));
        // }
    }

</script>
<style lang="scss" scoped>
    #map {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
    }

    /*移除OSM的链接*/
    :deep(.ol-attribution) {
        display: none;
    }
</style>